﻿using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;

namespace Xrm.Framework.Test.Integration
{
    /// <summary>
    /// Base Class for all Dynamics CRM Workflow Activities Integration Tests
    /// </summary>
    public abstract class WFActivityIntegrationTest : AsyncIntegrationTest
    {
        #region Instance Variables

        private Guid _workflowId;
        private Guid _entityId;

        #endregion

        #region Properties

        protected override string AsyncOperationName => GetType().Name;

        protected override int AsyncOperationType => 10;

        #endregion

        #region Constructors

        public WFActivityIntegrationTest()
        {
        }

        public WFActivityIntegrationTest(IOrganizationService service)
            : base(service)
        {
        }

        #endregion

        #region Test Methods

        protected override void Setup()
        {
            _entityId = SetupPrimaryEntity();
            if (_entityId == null || _entityId == Guid.Empty)
                throw new ArgumentNullException("Entity ID", "Record ID (GUID) cannot be null or Empty");

            var query = new QueryByAttribute("workflow");
            query.ColumnSet = new ColumnSet("workflowid", "type", "ondemand", "statecode");
            query.Attributes.AddRange("name", "type");
            query.Values.AddRange(AsyncOperationName, (int) ProcessType.Defition);

            EntityCollection ec = OrganizationService.RetrieveMultiple(query);

            if (ec.Entities.Count == 0)
                throw new Exception($"A workflow with name '{AsyncOperationName}' couldn't be found");
            if (ec.Entities.Count > 1)
                throw new Exception($"Two or more workflows with name '{AsyncOperationName}' were found");

            Entity processRecord = ec[0];
            if (!processRecord.Contains("ondemand") || ((Boolean) processRecord["ondemand"]) != true)
                throw new Exception("Process must be configured to run On Demand");

            if (!processRecord.Contains("statecode") || (((OptionSetValue) processRecord["statecode"]).Value) != (int) ProcessStatus.Activated)
                throw new Exception("Process must be activated");

            _workflowId = processRecord.Id;
            base.Setup();
        }

        protected override OrganizationRequest SetupTriggerRequest()
        {
            return new ExecuteWorkflowRequest()
            {
                EntityId = _entityId,
                WorkflowId = _workflowId
            };
        }

        #endregion

        #region Abstract Methods

        protected abstract Guid SetupPrimaryEntity();

        #endregion
    }
}